package com.xiyuan.smartutils;

import com.xiyuan.smartutils.crypto.MD5;

import java.io.File;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * the description for class TempFileClear
 *
 * @author xiyuan-lgz 2025-05-31 @version v1.0.0 新建与整理
 */
public final class TempFiles extends Thread {
    private static TempFiles instance;
    private static Set<String> tempFiles = new HashSet<>();
    private static String TEMP_DIR;
    private static String ROOT_DIR;
    private static String NATIVE_DIR;
    private static final String md5 = MD5.encodeUTF8(TempFiles.class.getName());
    private static volatile Boolean flag = false;
    
    /**
     * 添加临时 库文件文件
     *
     * @param bytes 文件内容
     * @param name  临时文件目录或者文件名
     * @return 临时文件路径， null 表示 写入失败
     */
    public static String addTempLibFile(byte[] bytes, String name) {
        
        if (!flag) {
            synchronized (flag) {
                if (!flag) {
                    flag = true;
                    init();
                }
            }
        }
        
        String filePath = NATIVE_DIR + "/" + StrUtils.trimLeft(StrUtils.trim(name), "/");
        if (bytes == null) {
            return null;
        }
        if (Files.exists(filePath)) {
            return filePath;
        }
        filePath = Files.write(filePath, bytes) ? filePath : null;
        if (filePath != null) {
            new File(filePath).deleteOnExit();
        }
        
        return filePath;
    }
    
    /**
     * 写入临时文件
     *
     * @param bytes 文件内容
     * @param name  临时文件目录
     * @return 临时文件路径， null 表示 写入失败
     */
    public static String addTempFile(byte[] bytes, String name) throws Exception {
        String filePath = TEMP_DIR + "/" + StrUtils.trimLeft(StrUtils.trim(name), "/");
        return Files.write(filePath, bytes) ? filePath : null;
    }
    
    public static boolean exists(String name) {
        return Files.exists(TEMP_DIR + "/" + StrUtils.trimLeft(StrUtils.trim(name), "/"));
    }
    
    public static String getTempDir() {
        return TEMP_DIR;
    }
    
    public static String getNativeDir() {
        return NATIVE_DIR;
    }
    
    public static List<String> getNativeDirs() {
        
        List<String> ls = Files.listFiles(new File(NATIVE_DIR), null)
                .stream()
                .map(r -> Files.toLinuxPath(r.getParentFile().getPath()))
                .distinct()
                .collect(Collectors.toList());
        if (!ls.contains(NATIVE_DIR)) ls.add(0, NATIVE_DIR);
        return ls;
    }
    
    private static Cleaner cleaner;
    
    public void run() {
        
        // try {
        //     cleaner.clean();
        // }
        // catch (Throwable e) {
        //     e.printStackTrace();
        // }
    }
    
    private static void init() {
        cleaner = new Cleaner(md5, 60 * 60 * 24 * 7);
        Runtime.getRuntime().addShutdownHook(instance);
        Thread thread = new Thread(() -> {
            try {
                AtomicBoolean init = new AtomicBoolean(false);
                int time = 5;
                Runnable handler = new Runnable() {
                    @Override
                    public void run() {
                        Files.writeUTF8(ROOT_DIR + "/" + md5, System.currentTimeMillis() + "");
                        if (init.get()) {
                            cleaner.clean();
                            Threads.sleepIgnoreException(1000 * time);
                        }
                        init.getAndSet(true);
                        Handlers.execute(this);
                    }
                };
                cleaner.clean();
                Threads.sleepIgnoreException(1000 * 10);
                handler.run();
            }
            catch (Exception ignored) {
                ignored.printStackTrace();
            }
        });
        thread.setDaemon(true);
        thread.start();
    }
    
    static {
        instance = new TempFiles();
        try {
            Path tempDir = Files.createTempDirectory(md5);
            ROOT_DIR = Files.toLinuxPath(tempDir.toFile().getPath());
            TEMP_DIR = ROOT_DIR + "/app";
            NATIVE_DIR = ROOT_DIR + "/native";
        }
        catch (Exception ignored) {}
        finally {
        
        }
    }
    
    
    static class Cleaner {
        
        private final String md5;
        private final int time;
        
        public Cleaner(String md5, int time) {
            this.md5 = md5;
            this.time = time;
        }
        
        private void clean() {
            File dir = new File(ROOT_DIR).getParentFile();
            File[] ls = dir.listFiles();
            for (File file : ls) {
                if (file.isFile()) {
                    continue;
                }
                
                long currentTime = System.currentTimeMillis();
                if (file.isDirectory() && file.getName().startsWith(md5)) {
                    String path = Files.toLinuxPath(file);
                    File file1 = new File(StrUtils.addEndsWith(path, "/") + md5);
                    if (file1.exists()) {
                        try {
                            String data = Files.readUTF8(file1);
                            long overTime = (currentTime - Long.parseLong(data)) / 1000;
                            if (overTime > time) {
                                // 删除
                                Files.deleteDirectory(path);
                            }
                        }
                        catch (Throwable ignored) {
                        }
                    }
                }
            }
        }
    }
}
